using Enough.Lego.Mindstorms.WP.Controls;
using Enough.Lego.Mindstorms.WP.Model;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Lego.Ev3.Core;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Navigation;

namespace Enough.Lego.Mindstorms.WP.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class MainViewModel : MyViewModelBase
    {
        TurtleSnapp3rController _controller;
        int _speedMax = 245;

        private string _openButtonNormal = "Assets/btn_open_normal.png";
        private string _openButtonPressed = "Assets/btn_open_pressed.png";
        private string _closeButtonNormal = "Assets/btn_close_normal.png";
        private string _closeButtonPressed = "Assets/btn_close_pressed.png";
        private string _leftButtonNormal = "Assets/btn_left_normal.png";
        private string _leftButtonPressed = "Assets/btn_left_pressed.png";
        private string _rightButtonNormal = "Assets/btn_right_normal.png";
        private string _rightButtonPressed = "Assets/btn_right_pressed.png";

        public RelayCommand TurnRightCommand { get; private set; }
        public RelayCommand StopTurningRightCommand { get; private set; }
        public RelayCommand TurnLeftCommand { get; private set; }
        public RelayCommand StopTurningLeftCommand { get; private set; }
        public RelayCommand StartOpeningCommand { get; private set; }
        public RelayCommand StopOpeningCommand { get; private set; }
        public RelayCommand StartClosingCommand { get; private set; }
        public RelayCommand StopClosingCommand { get; private set; }
        public RelayCommand StopEverything { get; private set; }
        public RelayCommand<EventArgs> NewCoordinates { get; private set; }
        public RelayCommand<EventArgs> StopMovement { get; private set; }
        public RelayCommand<object> BackKeyPressCommand { get; private set; }
        public RelayCommand TryAgainCommand { get; private set; }

        private string _statusText = "- - -";
        public string StatusText
        {
            get { return _statusText; }
            set
            {
                if (_statusText != value)
                {
                    _statusText = value;
                    RaisePropertyChanged();
                }
            }
        }

        private bool _errorMessage = false;
        public bool ErrorMessage
        {
            get { return _errorMessage; }
            set
            {
                if (_errorMessage != value)
                {
                    _errorMessage = value;
                    RaisePropertyChanged();
                }
            }
        }

        private bool _isBusy = false;
        public bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                if (_isBusy != value)
                {
                    _isBusy = value;
                    RaisePropertyChanged();
                }
            }
        }

        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                if (_isEnabled != value)
                {
                    _isEnabled = value;
                    RaisePropertyChanged();
                }
            }
        }

        private string _openButtonSource;
        public string OpenButtonSource
        {
            get { return _openButtonSource; }
            set
            {
                if (_openButtonSource != value)
                {
                    _openButtonSource = value;
                    RaisePropertyChanged();
                }
            }
        }

        private string _closeButtonSource;
        public string CloseButtonSource
        {
            get { return _closeButtonSource; }
            set
            {
                if (_closeButtonSource != value)
                {
                    _closeButtonSource = value;
                    RaisePropertyChanged();
                }
            }
        }

        private string _leftButtonSource;
        public string LeftButtonSource
        {
            get { return _leftButtonSource; }
            set
            {
                if (_leftButtonSource != value)
                {
                    _leftButtonSource = value;
                    RaisePropertyChanged();
                }
            }
        }

        private string _rightButtonSource;
        public string RightButtonSource
        {
            get { return _rightButtonSource; }
            set
            {
                if (_rightButtonSource != value)
                {
                    _rightButtonSource = value;
                    RaisePropertyChanged();
                }
            }
        }

        private int _timerMilliseconds;
        public int TimerMilliseconds
        {
            get { return _timerMilliseconds; }
            set
            {
                if (_timerMilliseconds != value)
                {
                    _timerMilliseconds = value;
                    RaisePropertyChanged();
                }
            }
        }

        private bool _frontBuffer = false;
        public bool FrontBuffer
        {
            get { return _frontBuffer; }
            set
            {
                if (_frontBuffer != value)
                {
                    _frontBuffer = value;
                    RaisePropertyChanged();
                }
            }
        }

        private bool _backBuffer = false;
        public bool BackBuffer
        {
            get { return _backBuffer; }
            set
            {
                if (_backBuffer != value)
                {
                    _backBuffer = value;
                    RaisePropertyChanged();
                }
            }
        }

        public MainViewModel()
        {
            _controller = new TurtleSnapp3rController();
            TurnRightCommand = new RelayCommand(turnRight);
            StopTurningRightCommand = new RelayCommand(stopTurningRight);
            TurnLeftCommand = new RelayCommand(turnLeft);
            StopTurningLeftCommand = new RelayCommand(stopTurningLeft);
            StopEverything = new RelayCommand(stopEverything);
            NewCoordinates = new RelayCommand<EventArgs>(newCoordinates);
            StopMovement = new RelayCommand<EventArgs>(stopMovement);
            BackKeyPressCommand = new RelayCommand<object>(onBackKeyPressed);
            StartOpeningCommand = new RelayCommand(startOpening);
            StopOpeningCommand = new RelayCommand(stopOpening);
            StartClosingCommand = new RelayCommand(startClosing);
            StopClosingCommand = new RelayCommand(stopClosing);
            TryAgainCommand = new RelayCommand(tryAgain);
            OpenButtonSource = _openButtonNormal;
            CloseButtonSource = _closeButtonNormal;
            LeftButtonSource = _leftButtonNormal;
            RightButtonSource = _rightButtonNormal;

            ConnectWithBrick();
        }

        private void onBackKeyPressed(object obj)
        {
            _controller.Brick.BrickChanged -= Brick_BrickChanged;
        }

        private async void ConnectWithBrick()
        {
            try
            {
                await _controller.ConnectAsync();
                StatusText = "Ready";
                _controller.Brick.BrickChanged += Brick_BrickChanged;
                ErrorMessage = false;
                IsBusy = false;
            }
            catch (Exception)
            {
                StatusText = "Error!";
                ErrorMessage = true;
                IsBusy = false;
                IsEnabled = true;
            }
        }

        private void tryAgain()
        {
            _controller.DisconnectBrick();
            ConnectWithBrick();
            IsBusy = true;
            IsEnabled = false;
        }

        private async void newCoordinates(EventArgs e)
        {
            if (_controller.IsConnected)
            {
                double newSpeed = ((MyCoordinates)e).Speed;
                double newDirection = ((MyCoordinates)e).Direction;

                double leftSpeed = 0;
                double rightSpeed = 0;

                if (newSpeed > _speedMax)
                {
                    newSpeed = _speedMax;
                }

                if (newDirection > 0 && newDirection < 91)
                {
                    if (!FrontBuffer)
                    {
                        rightSpeed = (((90 - newDirection) / 90) * (newSpeed / _speedMax)) * 100;
                        leftSpeed = (newSpeed / _speedMax) * 100;
                    }
                }
                else if (newDirection > 90 && newDirection < 181)
                {
                    if (!BackBuffer)
                    {
                        rightSpeed = (((newDirection - 90) / 90) * (newSpeed / _speedMax)) * (-100);
                        leftSpeed = (newSpeed / _speedMax) * (-100);
                    }
                }
                else if (newDirection > 180 && newDirection < 271)
                {
                    if (!BackBuffer)
                    {
                        rightSpeed = (newSpeed / _speedMax) * (-100);
                        leftSpeed = (((90 - (newDirection - 180)) / 90) * (newSpeed / _speedMax)) * (-100);
                    }
                }
                else if (newDirection > 270 && newDirection < 360)
                {
                    if (!FrontBuffer)
                    {
                        rightSpeed = (newSpeed / _speedMax) * 100;
                        leftSpeed = (((newDirection - 270) / 90) * (newSpeed / _speedMax)) * (100);
                    }
                }

                await _controller.MoveAsync((int)leftSpeed, (int)rightSpeed);

                StatusText = "Moving";
            }
        }

        private async void stopMovement(EventArgs e)
        {
            if (_controller.IsConnected)
            {
                await _controller.StopMovementAsync();
                await _controller.StopOpenCloseAsync();
                StatusText = "Moved";
            }
        }

        private async void startOpening()
        {
            if (_controller.IsConnected)
            {
                OpenButtonSource = _openButtonPressed;
                await _controller.OpenAsync();
            }
        }

        private async void stopOpening()
        {
            if (_controller.IsConnected)
            {
                OpenButtonSource = _openButtonNormal;
                await _controller.StopOpenCloseAsync();
            }
        }

        private async void startClosing()
        {
            if (_controller.IsConnected)
            {
                CloseButtonSource = _closeButtonPressed;
                await _controller.CloseAsync();
            }
        }

        private async void stopClosing()
        {
            if (_controller.IsConnected)
            {
                CloseButtonSource = _closeButtonNormal;
                await _controller.StopOpenCloseAsync();
            }
        }

        private async void turnRight()
        {
            if (_controller.IsConnected)
            {
                RightButtonSource = _rightButtonPressed;
                await _controller.MoveAsync(50, -50);
            }
        }

        private async void stopTurningRight()
        {
            if (_controller.IsConnected)
            {
                RightButtonSource = _rightButtonNormal;
                await _controller.StopMovementAsync();
            }
        }

        private async void turnLeft()
        {
            if (_controller.IsConnected)
            {
                LeftButtonSource = _leftButtonPressed;
                await _controller.MoveAsync(-50, 50);
            }
        }

        private async void stopTurningLeft()
        {
            if (_controller.IsConnected)
            {
                LeftButtonSource = _leftButtonNormal;
                await _controller.StopMovementAsync();
            }
        }
        
        private async void stopEverything()
        {
            if (_controller.IsConnected)
            {
                await _controller.StopMovementAsync();
                await _controller.StopOpenCloseAsync();
                StatusText = "Stopped";
            }
        }

        private async void Brick_BrickChanged(object sender, BrickChangedEventArgs e)
        {
            if (_controller.IsConnected)
            {
                if (e.Ports[InputPort.One].SIValue == 1 || e.Ports[InputPort.Two].SIValue == 1)
                {
                    await _controller.StopMovementAsync();
                }

                if (e.Ports[InputPort.One].SIValue == 1)
                {
                    FrontBuffer = true;
                    BackBuffer = false;
                }
                else if (e.Ports[InputPort.Two].SIValue == 1)
                {
                    BackBuffer = true;
                    FrontBuffer = false;
                }
                else
                {
                    FrontBuffer = false;
                    BackBuffer = false;
                }
            }
        }
    }
}